package com.whmskj.xjlhsc.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.whmskj.xjlhsc.entity.EquipmentMtnPlanAllocation;
import com.whmskj.xjlhsc.entity.WbPlanDetal;
import com.whmskj.xjlhsc.exception.BusinessException;
import com.whmskj.xjlhsc.jitapi.entity.Dict;
import com.whmskj.xjlhsc.jitapi.entity.InventoryRecord;
import com.whmskj.xjlhsc.jitapi.mapper.DictMapper;
import com.whmskj.xjlhsc.jitapi.mapper.InventoryMapper;
import com.whmskj.xjlhsc.mapper.WbPlanMapper;
import com.whmskj.xjlhsc.entity.WbPlan;
import com.whmskj.xjlhsc.schedul.delayTask.DelayTask;
import com.whmskj.xjlhsc.schedul.delayTask.DelayTaskScheduler;
import com.whmskj.xjlhsc.service.EquipmentMtnPlanAllocationService;
import com.whmskj.xjlhsc.service.WbPlanDetalService;
import com.whmskj.xjlhsc.service.WbPlanService;
import com.whmskj.xjlhsc.utils.SCUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.whmskj.xjlhsc.exception.ExceptionText.*;

/**
 * @author lk
 * @since 2025-06-10 08:57:31
 */
@Service
@Slf4j
public class WbPlanServiceImpl extends ServiceImpl<WbPlanMapper, WbPlan> implements WbPlanService {


    @Autowired
    private WbPlanMapper wbPlanMapper;
    @Autowired
    private InventoryMapper inventoryMapper;
    @Autowired
    private WbPlanDetalService wbPlanDetalService;
    @Autowired
    private EquipmentMtnPlanAllocationService equipmentMtnPlanAllocationService;
    @Autowired
    private DictMapper dictMapper;

    @Override
    public Page<WbPlan> findPage(WbPlan params) {
        LambdaQueryWrapper<WbPlan> query = Wrappers.lambdaQuery(WbPlan.class);
        query.eq(ObjectUtil.isNotNull(params.getYmDate()), WbPlan::getYmDate, params.getYmDate());
        query.eq(ObjectUtil.isNotNull(params.getItemType()), WbPlan::getItemType, params.getItemType());
        query.eq(ObjectUtil.isNotNull(params.getWorkshop()), WbPlan::getWorkshop, params.getWorkshop());
        return wbPlanMapper.selectPage(SCUtil.getPage(), query);
    }

    @Override
    public List<WbPlan> findList(WbPlan params) {
        LambdaQueryWrapper<WbPlan> query = Wrappers.lambdaQuery(WbPlan.class);
        if (ObjectUtil.isNotNull(params)) {
            query.eq(ObjectUtil.isNotNull(params.getWorkshop()), WbPlan::getWorkshop, params.getWorkshop());
            query.eq(StringUtils.isNotEmpty(params.getYmDate()), WbPlan::getYmDate, params.getYmDate());
            query.eq(ObjectUtil.isNotNull(params.getItemType()), WbPlan::getItemType, params.getItemType());
        }

        return wbPlanMapper.selectList(query);
    }

    @Override
    public WbPlan findById(Long id) {
        return wbPlanMapper.selectById(id);
    }

    @Override
    public boolean insert(WbPlan wbPlan) {
        return save(wbPlan);
    }

    @Override
    public boolean update(WbPlan wbPlan) {
        return updateById(wbPlan);
    }

    @Override
    public int delete(Long id) {
        return wbPlanMapper.deleteById(id);
    }


    @Override
    @Transactional(rollbackFor = Throwable.class)
    public boolean addWbPlan(WbPlan wbPlan) {
        valid(wbPlan);
        String ymDate = wbPlan.getYmDate();

        wbPlan.setPlanNo(getPlanNo(wbPlan));
        save(wbPlan);

        Long maintenancePlanId = wbPlan.getMaintenancePlanId();
        List<LinkedHashMap<String, Object>> planDetailList = wbPlan.getPlanDetailList();

        //todo 是否会有key重复
        Map<String, InventoryRecord> titleMapId = inventoryMapper.getInventoryRecordByYm(ymDate).stream().collect(Collectors.toMap(InventoryRecord::getShowTitle, Function.identity()));

        int rowIndex = 0;

        List<WbPlanDetal> saveRecordList = new ArrayList<>();
        for (Map<String, Object> map : planDetailList) {

            String processDict = map.get("title").toString();

            for (String key : map.keySet()) {
                //标题最左列
                String value = ObjectUtil.isNotNull(map.get(key)) ? map.get(key).toString() : "";
                InventoryRecord inventoryRecord = titleMapId.get(key);
                WbPlanDetal wbPlanDetal = new WbPlanDetal();
                wbPlanDetal.setWbPlanId(maintenancePlanId);
                wbPlanDetal.setInventoryDateId(ObjectUtil.isNotNull(inventoryRecord) ? inventoryRecord.getRecordId() : 0);
                wbPlanDetal.setProcessDict(processDict);
                wbPlanDetal.setValue(value);
                wbPlanDetal.setRowIndex(rowIndex);
                wbPlanDetal.setFieldSort(ObjectUtil.isNotNull(inventoryRecord) ? inventoryRecord.getDate() : "0");
                saveRecordList.add(wbPlanDetal);
            }
            rowIndex++;
        }
        wbPlanDetalService.saveBatch(saveRecordList);
        List<EquipmentMtnPlanAllocation> allocationList = wbPlan.getAllocationList();
        allocationList.forEach(cur -> cur.setWbPlanId(maintenancePlanId));
        equipmentMtnPlanAllocationService.saveBatch(allocationList);
        return Boolean.TRUE;
    }

    /**
     * 获取添加的维保计划编号
     *
     * @param wbPlan
     * @return
     */
    private String getPlanNo(WbPlan wbPlan) {
        String ymDate = wbPlan.getYmDate();
        LambdaQueryWrapper<WbPlan> countQe = Wrappers.lambdaQuery();
        String replace = ymDate.replace("-", "");
        countQe.likeRight(WbPlan::getPlanNo, "WJ" + replace);
        long count = count(countQe);
        return "WJ" + replace + String.format("%02d", ++count);
    }

    private static void valid(WbPlan wbPlan) {
        List<LinkedHashMap<String, Object>> planDetailList = wbPlan.getPlanDetailList();
        if (CollectionUtil.isEmpty(planDetailList)) throw new BusinessException(PLAN_DETAIL_TEXT);

        List<EquipmentMtnPlanAllocation> allocationList = wbPlan.getAllocationList();
        if (CollectionUtil.isEmpty(allocationList)) throw new BusinessException(ALLOCATION_LIST);
    }


    @Override
    public WbPlan findById_c(Long id) {
        WbPlan wbPlan = getById(id);
        LambdaQueryWrapper<WbPlanDetal> qe = new LambdaQueryWrapper<>();
        qe.eq(WbPlanDetal::getWbPlanId, id);
        List<WbPlanDetal> detailList = wbPlanDetalService.list(qe);

        Map<Integer, List<WbPlanDetal>> rowsMap = detailList.stream().collect(Collectors.groupingBy(WbPlanDetal::getRowIndex));

        List<Integer> rowIndexs = rowsMap.keySet().stream().sorted(Comparator.comparing(Integer::intValue)).toList();

        List<LinkedHashMap<String, Object>> planDetailList = new ArrayList<>();
        Map<Integer, String> idMapShowTitle = inventoryMapper.getInventoryRecordByYm(wbPlan.getYmDate()).stream().collect(Collectors.toMap(InventoryRecord::getRecordId, InventoryRecord::getShowTitle));

        for (Integer rowIndex : rowIndexs) {
            List<WbPlanDetal> wbPlanDetals = rowsMap.get(rowIndex);
            wbPlanDetals.sort(Comparator.comparing(WbPlanDetal::getFieldSort));

            LinkedHashMap<String, Object> rowEntity = new LinkedHashMap<>();
            for (WbPlanDetal wbPlanDetal : wbPlanDetals) {
                //FileSort与rowIndex定位到那个元素
                rowEntity.put("rowIndex", rowIndex);
                rowEntity.put("planId", wbPlan.getMaintenancePlanId().toString());
                if (wbPlanDetal.getInventoryDateId() == 0) {
                    //标题最左
                    rowEntity.put("title", wbPlanDetal.getValue());
                } else {
                    //各项列的值
                    rowEntity.put(idMapShowTitle.get(wbPlanDetal.getInventoryDateId()), wbPlanDetal.getValue());
                }
            }
            planDetailList.add(rowEntity);
        }
        wbPlan.setPlanDetailList(planDetailList);

        //查询分配
        LambdaQueryWrapper<EquipmentMtnPlanAllocation> eq = new LambdaQueryWrapper<EquipmentMtnPlanAllocation>().eq(EquipmentMtnPlanAllocation::getWbPlanId, id);
        List<EquipmentMtnPlanAllocation> allocationList = equipmentMtnPlanAllocationService.list(eq);
        wbPlan.setAllocationList(allocationList);
        return wbPlan;
    }


    @Override
    @Transactional(rollbackFor = Throwable.class)
    public boolean update_c(WbPlan wbPlan) {
        update(wbPlan);
        //删除行有删除操作
        Long maintenancePlanId = wbPlan.getMaintenancePlanId();
        LambdaQueryWrapper<WbPlanDetal> delQe = Wrappers.lambdaQuery();
        delQe.eq(WbPlanDetal::getWbPlanId, maintenancePlanId);
        wbPlanDetalService.remove(delQe);

        //更新详情
        List<LinkedHashMap<String, Object>> planDetailList = wbPlan.getPlanDetailList();
        if (CollectionUtil.isEmpty(planDetailList)) throw new BusinessException(PLAN_DETAIL_NOT_EMPTY);


        Map<String, InventoryRecord> titleMapId = inventoryMapper.getInventoryRecordByYm(wbPlan.getYmDate()).stream().collect(Collectors.toMap(InventoryRecord::getShowTitle, Function.identity()));

        int rowIndex = 0;

        List<WbPlanDetal> saveRecordList = new ArrayList<>();
        for (Map<String, Object> map : planDetailList) {

            String processDict = map.get("title").toString();

            for (String key : map.keySet()) {
                //标题最左列
                String value = ObjectUtil.isNotNull(map.get(key)) ? map.get(key).toString() : "";
                InventoryRecord inventoryRecord = titleMapId.get(key);
                WbPlanDetal wbPlanDetal = new WbPlanDetal();
                wbPlanDetal.setWbPlanId(maintenancePlanId);
                wbPlanDetal.setInventoryDateId(ObjectUtil.isNotNull(inventoryRecord) ? inventoryRecord.getRecordId() : 0);
                wbPlanDetal.setProcessDict(processDict);
                wbPlanDetal.setValue(value);
                wbPlanDetal.setRowIndex(rowIndex);
                wbPlanDetal.setFieldSort(ObjectUtil.isNotNull(inventoryRecord) ? inventoryRecord.getDate() : "0");
                saveRecordList.add(wbPlanDetal);
            }
            rowIndex++;
        }
        wbPlanDetalService.saveBatch(saveRecordList);

        //更新指派人信息
        equipmentMtnPlanAllocationService.remove(new LambdaQueryWrapper<EquipmentMtnPlanAllocation>().eq(EquipmentMtnPlanAllocation::getWbPlanId, maintenancePlanId));
        wbPlan.getAllocationList().forEach(cur -> cur.setWbPlanId(maintenancePlanId));
        equipmentMtnPlanAllocationService.saveBatch(wbPlan.getAllocationList());
        return Boolean.TRUE;
    }


    @Override
    public List<WbPlanDetal> getDeviceListWithToday(Long wbPlanId, LocalDate nwoDate) {
        return wbPlanMapper.getDeviceListWithToday(wbPlanId, nwoDate);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void copyGeneratorNext(List<Long> maintenancePlanIds) {
        valid(maintenancePlanIds);
        Long maintenancePlanId = maintenancePlanIds.get(0);
        WbPlan wbPlan = getById(maintenancePlanId);
        WbPlan save = new WbPlan();
        BeanUtils.copyProperties(wbPlan, save, "maintenancePlanId", "planNo");
        YearMonth yearMonth = YearMonth.parse(wbPlan.getYmDate()).plusMonths(1);
        save.setYmDate(yearMonth.format(DateTimeFormatter.ofPattern("yyyy-MM")));
        save.setPlanNo(getPlanNo(save));
        save(save);
        equipmentMtnPlanAllocationService.copyGeneratorNext(maintenancePlanId, save.getMaintenancePlanId());
        wbPlanDetalService.copyGeneratorNext(maintenancePlanId, save.getMaintenancePlanId());
    }

    private static void valid(List<Long> maintenancePlanIds) {
        if (CollectionUtil.isEmpty(maintenancePlanIds)) throw new BusinessException(SELECT_PLAN_NOT_EMPTY);

        if (maintenancePlanIds.size() > 1) throw new BusinessException(ONLY_ONE_PLAN);
    }

    @Override
    public void export(WbPlan params, HttpServletResponse response) {
        List<WbPlan> list = findList(params);

        Map<Integer, String> dictMap = dictMapper.all().stream().collect(Collectors.toMap(Dict::getValue, Dict::getLabel));
        for (WbPlan wbPlan : list) {
            wbPlan.setTypeLabel(dictMap.get(wbPlan.getType()));
            wbPlan.setStateLabel(dictMap.get(wbPlan.getState()));
            wbPlan.setWorkshopLabel(dictMap.get(wbPlan.getWorkshop()));
            wbPlan.setItemTypeLabel(dictMap.get(wbPlan.getItemType()));
        }
        ExcelWriter excelWriter = null;
        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("维保计划" + LocalDate.now().toString() + ".xlsx", StandardCharsets.UTF_8));

            excelWriter = EasyExcel.write(response.getOutputStream(), WbPlan.class).build();
            WriteSheet writeSheet = EasyExcel.writerSheet("维保计划").build();
            excelWriter.write(list, writeSheet);
        } catch (IOException e) {
            throw new RuntimeException("导出失败", e);
        } finally {
            if (excelWriter != null) {
                excelWriter.finish();
            }


        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete_c(Long id) {
        removeById(id);
        wbPlanDetalService.remove(new LambdaQueryWrapper<WbPlanDetal>().eq(WbPlanDetal::getWbPlanId, id));
        equipmentMtnPlanAllocationService.remove(new LambdaQueryWrapper<EquipmentMtnPlanAllocation>().eq(EquipmentMtnPlanAllocation::getWbPlanId, id));
    }
}